package com.example.widget_lib.widget;

import com.example.widget_lib.utils.LogUtil;
import com.example.widget_lib.utils.PxUtil;
import com.example.widget_lib.widget.base.BaseGradientView;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.*;
import ohos.agp.utils.Color;
import ohos.agp.utils.Point;
import ohos.app.Context;

import java.util.List;

/**
 * 渐变曲线自定义
 */
public class GradientLine extends BaseGradientView implements Component.DrawTask {

    private Paint mPaint; // 曲线画笔
    private Paint mImaPaint; // 虚线画笔
    private Paint mPointPaint; // 圆点
    private Point control1, control2; // 控制点
    private float mRadius; // 小圆半径
    private float mImaLineL; // 曲线长度
    private int mLineW; // 图形长度
    private float mRadian; // 控制点弧度

    public GradientLine(Context context, AttrSet attrs) {
        super(context, attrs, 0);
        addDrawTask(this);
    }

    @Override
    public void addDrawTask(DrawTask task) {
        super.addDrawTask(task);
        task.onDraw(this, mCanvasForTaskOverContent);
    }

    @Override
    protected void init() {
        super.init();
        mPaint = new Paint();
        mPaint.setStrokeWidth(8f);
//        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.STROKE_STYLE);
        mPaint.setAntiAlias(true);

        mPointPaint = new Paint();
        mPointPaint.setStyle(Paint.Style.STROKE_STYLE);
        mPointPaint.setColor(Color.GREEN);
        mPointPaint.setStrokeWidth(5f);
        mPointPaint.setAntiAlias(true);

        mImaPaint = new Paint();
        mImaPaint.setStyle(Paint.Style.STROKE_STYLE);
        mImaPaint.setStrokeWidth(5f);
        mImaPaint.setColor(new Color(Color.rgb(200, 200, 200)));
        mImaPaint.setPathEffect(new PathEffect(new float[]{16, 4}, 0)); // 参数：数组（param1：线段长度，线段间的间距）

        control1 = new Point(0f, 0f);
        control2 = new Point(0f, 0f);

        mRadius = PxUtil.vp2px(2.4f);
        mLineW = (int) PxUtil.vp2px(80f);
        mRadian = (1.4f / 3); // 控制点弧度
    }

    public void setMode(int mode) {
        mMode = Mode.values()[mode];
        if (mIsAnim && mIsRunging) { // 如果当前动画还没结束，有开启其他模式的动画，需要将动画开关关闭，避免同个控件同时刷新数据导致的图形问题
            mIsAnim = false;
        }
        invalidate();
    }

    public void setRadian(float radian) {
        mRadian = radian;
    }

    private void caclControPoint(int w, int h) {
        if (mMode == Mode.Up) {
            control1.modify(w * mRadian, h - mRadius * 2 - mPointPaint.getStrokeWidth());
            control2.modify(w * (1.f - mRadian), mRadius);
        } else if (mMode == Mode.Down) {
            control1.modify(w * mRadian, mRadius + mPointPaint.getStrokeWidth());
            control2.modify(w * (1.f - mRadian), h - mRadius * 2 - mPointPaint.getStrokeWidth());
        }
    }

//    @Override
//    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//        final int width = measureSize(widthMeasureSpec);
//        final int height = measureSize(heightMeasureSpec);
//        log("onMeasure-->width = " + width + "->height = " + height);
//        setMeasuredDimension(width, height);
//    }

    @Override
    public void onDraw(Component component, Canvas canvas) {

        mView_W = getWidth();
        mView_H = getHeight();

        caclControPoint(mView_W, mView_H);

        if (mMode == Mode.Flat) {
//            if (mIsAnim) {
//                if (mCurrFlatPoint == null) {
//                    mCurrFlatPoint = new GradientPoint(mRadius * 2 + mPointPaint.getStrokeWidth(), mView_H / 2 - mPaint.getStrokeWidth() / 2);
//                    startAnimByFlat(mCurrFlatPoint.getX(), mCurrFlatPoint.getY(),
//                            mView_W - mRadius * 2 - mPointPaint.getStrokeWidth(), mView_H / 2 - mPaint.getStrokeWidth() / 2);
//                } else {
//                    drawFlat(canvas, mView_W, mView_H);
//                }
//            } else {
//                mCurrFlatPoint = new GradientPoint(mView_W - mRadius * 2 - mPointPaint.getStrokeWidth(),
//                        mView_H / 2 - mPaint.getStrokeWidth() / 2);
//                drawFlat(canvas, mView_W, mView_H);
//            }
            if (mIsAnim && !mIsRunging) {
                drawFlatByAnim();
            } else {
                drawFlat(canvas, mIsAnim);
            }
        } else if (mMode == Mode.Up) {
            if (mIsAnim && !mIsRunging) {
                drawUpByAnim();
            } else {
                drawUp(canvas, mIsAnim);
            }
        } else if (mMode == Mode.Down) {
            if (mIsAnim && !mIsRunging) {
                drawDownByAnim();
            } else {
                drawDown(canvas, mIsAnim);
            }
        }
    }

//    private int measureSize(int measureSpec) {
//        int result;
//        int mode = MeasureSpec.getMode(measureSpec);
//        int size = MeasureSpec.getSize(measureSpec);
//        switch (mode) {
//            case MeasureSpec.EXACTLY:
//                result = size;
//                break;
//            default:
//                result = mLineW;
//                break;
//        }
//        return result;
//    }

//    @Override
//    protected void onSizeChanged(int w, int h, int oldw, int oldh) { // 控件大小发生改变,invalidate之行不会调用本方法
//        super.onSizeChanged(w, h, oldw, oldh);
//        log("->>>>>>onSizeChanged...(w * mRadian) = " + w * mRadian + "->(w * 1 / 4) = " + (w * 1 / 4) + "->w = " + w);
//        caclControPoint(w, h);
//    }

//    @Override
//    protected void onLayout(boolean changed, int left, int top, int right, int bottom) { // requestLayout会重新调用该方法
//        super.onLayout(changed, left, top, right, bottom);
//        Log.d(TAG,"->>>>>>onLayout->w = " + (right - left));
//    }

    @Override
    protected void drawBezierPoint(List<Point> bezierPoints, Canvas canvas, Mode mode) {
        if (mode == Mode.None) {
            return;
        }

        if (mode == Mode.Up) {
            upLgMoreConfig(canvas);
        } else if (mode == Mode.Down) {
            downLgMoreCofig(canvas);
        } else if (mode == Mode.Flat) {
            flatLgMoreConfig(canvas);
        }

        Path path = new Path();
        path.moveTo(bezierPoints.get(0).getPointX(), bezierPoints.get(0).getPointY());

        int index = 1;
        int var6 = bezierPoints.size() - 1;
        if (index <= var6) {
            while (true) {
                path.lineTo(bezierPoints.get(index).getPointX(), bezierPoints.get(index).getPointY());
                if (index == var6) {
                    break;
                }
                ++index;
            }
        }
        canvas.drawPath(path, mPaint);
    }

//    private GradientPoint mCurrFlatPoint;
//
//    private void startAnimByFlat(float start_x, float start_y, float end_x, float end_y) {
//        GradientPoint startPoint = new GradientPoint(start_x, start_y);
//        GradientPoint endPoint = new GradientPoint(end_x, end_y);
//        ValueAnimator animator = ValueAnimator.ofObject(new GradientEvaluator(), startPoint, endPoint);
//        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
//            @Override
//            public void onAnimationUpdate(ValueAnimator animation) {
//                invalidate();
//                mCurrFlatPoint = (GradientPoint) animation.getAnimatedValue();
//            }
//        });
//        animator.addListener(new AnimatorListenerAdapter() {
//            @Override
//            public void onAnimationEnd(Animator animation) {
//                super.onAnimationEnd(animation);
////                        mCurrFlatPoint = null;
//            }
//        });
//        animator.setDuration(mAnimDuration);
//        animator.start();
//    }

    private void flatLgMoreConfig(Canvas canvas) {
        mPaint.setShader(null, Paint.ShaderType.LINEAR_SHADER);
        mPaint.setColor(new Color(Color.rgb(88, 181, 250)));
        // 画左右圆点
        mPointPaint.setShader(null, Paint.ShaderType.LINEAR_SHADER);
        mPointPaint.setColor(new Color(Color.rgb(88, 181, 250)));
        canvas.drawCircle(mRadius + mPointPaint.getStrokeWidth(), mView_H / 2 - mPaint.getStrokeWidth() / 2, mRadius, mPointPaint);
        canvas.drawCircle(mView_W - mRadius - mPointPaint.getStrokeWidth(), mView_H / 2 - mPaint.getStrokeWidth() / 2, mRadius, mPointPaint);
    }

    @Override
    protected void drawFlat(Canvas canvas, boolean isAnim) {
        if (isAnim) {
            updatePath(canvas, getPoints(), mMode);
        } else {
            flatLgMoreConfig(canvas);
            Point sp = new Point(mRadius * 2 + mPointPaint.getStrokeWidth(),
                    mView_H / 2 - mPaint.getStrokeWidth() / 2);
            Point ep = new Point(mView_W - mRadius * 2 - mPointPaint.getStrokeWidth(),
                    mView_H / 2 - mPaint.getStrokeWidth() / 2);

            LogUtil.loge("=xx===" + sp.getPointX());
            LogUtil.loge("=yy===" + sp.getPointY());
            canvas.drawLine(sp, ep, mPaint);
        }
    }

    @Override
    protected void drawFlatByAnim() {
        clearPointsAll();
        float y = mView_H / 2 - mPaint.getStrokeWidth() / 2;
        LogUtil.loge("=x==" + (mRadius * 2 + mPointPaint.getStrokeWidth()));
        LogUtil.loge("=y==" + y);
        // 起始点
        addPoint(mRadius * 2 + mPointPaint.getStrokeWidth(), y);
        // 结束点
        addPoint(mView_W - mRadius * 2 - mPointPaint.getStrokeWidth(), y);
        startAnim();
    }

    private void upLgMoreConfig(Canvas canvas) {
        Point sp = new Point(mRadius * 2, control1.getPointY());
        Point ep = new Point(mView_W / 2, control2.getPointY() + PxUtil.vp2px(2));

        Color sc = new Color(Color.rgb(255, 196, 0));
        Color ec = new Color(Color.rgb(255, 105, 83));
        LinearShader shader = new LinearShader(new Point[]{sp, ep}, null, new Color[]{sc, ec}, Shader.TileMode.CLAMP_TILEMODE);
        mPaint.setShader(shader, Paint.ShaderType.LINEAR_SHADER);

        // 画虚线
        Point sp1 = new Point(mView_W - mRadius - mPointPaint.getStrokeWidth(),
                mRadius * 2 + mPointPaint.getStrokeWidth());
        Point ep1 = new Point(mView_W - mRadius - mPointPaint.getStrokeWidth(),
                mView_H - mRadius * 2 - mPointPaint.getStrokeWidth());
        canvas.drawLine(sp1, ep1, mImaPaint);

        // 画圆点
        mPointPaint.setShader(shader, Paint.ShaderType.LINEAR_SHADER);
        canvas.drawCircle(mRadius + mPointPaint.getStrokeWidth(),
                mView_H - mRadius - mPointPaint.getStrokeWidth(),
                mRadius, mPointPaint);
        canvas.drawCircle(mView_W - mRadius - mPointPaint.getStrokeWidth(),
                control2.getPointY() + PxUtil.vp2px(2),
                mRadius, mPointPaint);
    }

    @Override
    protected void drawUp(Canvas canvas, boolean isAnim) {
        // 设置渐变曲线配置
        if (isAnim) {
            updatePath(canvas, getPoints(), mMode);
        } else {
            upLgMoreConfig(canvas);
            Path path = new Path();
            path.moveTo(mRadius * 2 + mPointPaint.getStrokeWidth(),
                    mView_H - mRadius - mPointPaint.getStrokeWidth());
            Point p1 = new Point(control1.getPointX(), control1.getPointY());
            Point p2 = new Point(control2.getPointX(), control2.getPointY());
            Point p3 = new Point(mView_W - (mRadius * 2) - mPointPaint.getStrokeWidth(),
                    control2.getPointY() + PxUtil.vp2px(2));
            path.cubicTo(p1, p2, p3);
            canvas.drawPath(path, mPaint);
        }
    }

    @Override
    protected void drawUpByAnim() {
        clearPointsAll();
        // 起始点
        addPoint(mRadius * 2 + mPointPaint.getStrokeWidth(), mView_H - mRadius - mPointPaint.getStrokeWidth());
        // 控制点1
        addPoint(control1.getPointX(), control1.getPointY());
        // 控制点2
        addPoint(control2.getPointX(), control2.getPointY());
        // 结束点
        addPoint(mView_W - (mRadius * 2) - mPointPaint.getStrokeWidth(), control2.getPointY() + PxUtil.vp2px(2));
        startAnim();
    }

    private void downLgMoreCofig(Canvas canvas) {
        // 设置渐变曲线配置
        float y0 = control1.getPointY();
        Point sp = new Point(mRadius * 2, y0);
        Point ep = new Point(mView_W / 2, control2.getPointY() + PxUtil.vp2px(2));
        Point[] points = new Point[]{sp, ep};
        Color sc = new Color(Color.rgb(88, 181, 250));
        Color ec = new Color(Color.rgb(101, 226, 175));
        Color[] colors = new Color[]{sc, ec};
        LinearShader shader = new LinearShader(points, null, colors, Shader.TileMode.CLAMP_TILEMODE);
        mPaint.setShader(shader, Paint.ShaderType.LINEAR_SHADER);

        // 画虚线
        Point start = new Point(mRadius + mPointPaint.getStrokeWidth(),
                mRadius * 2 + mPointPaint.getStrokeWidth());
        Point end = new Point(mRadius + mPointPaint.getStrokeWidth(),
                mView_H - mRadius * 2 - mPointPaint.getStrokeWidth());
        canvas.drawLine(start, end, mImaPaint);

        // 画圆点
        mPointPaint.setShader(shader, Paint.ShaderType.LINEAR_SHADER);
        canvas.drawCircle(mRadius + mPointPaint.getStrokeWidth(),
                control1.getPointY(), mRadius, mPointPaint);
        canvas.drawCircle(mView_W - mRadius - mPointPaint.getStrokeWidth(),
                control2.getPointY(), mRadius, mPointPaint);
    }

    @Override
    protected void drawDown(Canvas canvas, boolean isAnim) {
        if (isAnim) {
            updatePath(canvas, getPoints(), mMode);
        } else {
            downLgMoreCofig(canvas);

            Path path = new Path();
            path.moveTo(mRadius * 2 + mPointPaint.getStrokeWidth(),
                    mRadius + mPointPaint.getStrokeWidth());
            Point p1 = new Point(control1.getPointX(), control1.getPointY());
            Point p2 = new Point(control2.getPointX(), control2.getPointY());
            Point p3 = new Point(mView_W - (mRadius * 2) - mPointPaint.getStrokeWidth(), control2.getPointY());
            path.cubicTo(p1, p2, p3);
            canvas.drawPath(path, mPaint);
        }
    }

    @Override
    protected void drawDownByAnim() {
        clearPointsAll();
        // 起始点
        addPoint(mRadius * 2 + mPointPaint.getStrokeWidth(), mRadius + mPointPaint.getStrokeWidth());
        // 控制点1
        addPoint(control1.getPointX(), control1.getPointY());
        // 控制点2
        addPoint(control2.getPointX(), control2.getPointY());
        // 结束点
        addPoint(mView_W - (mRadius * 2) - mPointPaint.getStrokeWidth(), control2.getPointY());
        startAnim();
    }

    public interface LineMode {
        int FLAT = 0;
        int UP = 1;
        int DOWN = 2;
    }
}
